
use std::sync::mpsc::{SyncSender, Receiver};
use std::collections::HashMap;

use serde_json as json;
use serde_json::Value;

use game;
use net;

use super::Mapping;
use super::queue::Queue;

static mut ROOM_ID_INIT: u32 = 10000000;

fn new_room_id() -> u32{
    unsafe {
        if ROOM_ID_INIT > 99999999{
            ROOM_ID_INIT = 10000000;
        }
        ROOM_ID_INIT = ROOM_ID_INIT + 1;
        ROOM_ID_INIT
    }
}

///接收网络消息并处理
pub fn receive_from_net(receiver: &Receiver<net::message::Message>,
                        room_sender: &SyncSender<game::message::ChessCommand>,
                        player_sender: &SyncSender<net::message::Message>,
                        map: &mut Mapping,
                        queue: &mut Queue){
    loop{
        let ret = receiver.try_recv();
        match ret {
            Ok(message) => {
                let channel = message.channel_id();
                let content = message.data();
                let json: json::Result<Value> = json::from_str(content);
                match json {
                    Ok(value) => {
                        let code = &value["code"];
                        let body = &value["body"];
                        match code {
                            &Value::String(ref c) => {
                                match c.as_ref() {
                                    "player_connect" => {
                                        let message = handle_player_connect(channel, body, map);
                                        player_sender.send(message);
                                    },
                                    "player_match" => {
                                        let user = map.get_user(&channel);
                                        match user {
                                            Some(id) => handle_player_match(room_sender, player_sender,  queue, channel, *id, map),
                                            None => not_connect_error(player_sender, channel),//未注册连接
                                        }
                                    },
                                    "chess_put" => {
                                        let user = map.get_user(&channel);
                                        match user {
                                            Some(id) => {
                                                let room = map.get_room(id);
                                                match room {
                                                    Some(r) =>  handle_put_request(room_sender, body, *r, *id),
                                                    None => {
                                                        let data = json!({"code": "room_not_found", "message": "Error, can not find your chess room."});
                                                        let message = net::message::Message::new(channel, data.to_string());
                                                        player_sender.send(message);
                                                        error!("Can not find room with user id: {}", id);
                                                    }
                                                }
                                            },
                                            None => not_connect_error(player_sender, channel),//未注册连接
                                        }
                                    },
                                    "chess_kill" => {
                                        let user = map.get_user(&channel);
                                        match user {
                                            Some(id) => {
                                                let room = map.get_room(id);
                                                match room {
                                                    Some(r) =>  handle_kill_request(room_sender, body, *r, *id),
                                                    None => {
                                                        let data = json!({"code": "room_not_found", "message": "Error, can not find your chess room."});
                                                        let message = net::message::Message::new(channel, data.to_string());
                                                        player_sender.send(message);
                                                        error!("Can not find room with user id: {}", id);
                                                    }
                                                }
                                            },
                                            None => not_connect_error(player_sender, channel),//未注册连接
                                        }
                                    },
                                    //走子
                                    "chess_move" => {
                                        let user = map.get_user(&channel);
                                        match user {
                                            Some(id) => {
                                                let room = map.get_room(id);
                                                match room {
                                                    Some(r) =>  handle_kill_request(room_sender, body, *r, *id),
                                                    None => {
                                                        let data = json!({"code": "room_not_found", "message": "Error, can not find your chess room."});
                                                        let message = net::message::Message::new(channel, data.to_string());
                                                        player_sender.send(message);
                                                        error!("Can not find room with user id: {}", id);
                                                    }
                                                }
                                            },
                                            None => not_connect_error(player_sender, channel),//未注册连接
                                        }
                                    },
                                    "give_up" => {
                                        let user = map.get_user(&channel);
                                        match user {
                                            Some(id) => {
                                                let room = map.get_room(id);
                                                match room {
                                                    Some(r) =>  {
                                                        let message = game::message::ChessCommand::GiveUp(*r, *id);
                                                        room_sender.send(message);
                                                        info!("An user give up the chess. room: {}, user: {}", r, id);
                                                    },
                                                    None => {
                                                        let data = json!({"code": "room_not_found", "message": "Error, can not find your chess room."});
                                                        let message = net::message::Message::new(channel, data.to_string());
                                                        player_sender.send(message);
                                                        error!("Can not find room with user id: {}", id);
                                                    }
                                                }
                                            },
                                            None => not_connect_error(player_sender, channel),//未注册连接
                                        }
                                    }
                                    _ => error!("Unsupported message code: {}", c),
                                }
                            },
                            _ => error!("Invalid code: {:?}, want a string.", code),
                        }
                    },
                    Err(e) => error!("JSON data error, cannot format to json. error info: {:?}", e),
                }
            },
            Err(e) => break
        };
    }
}

///处理用户接入
fn handle_player_connect(channel: u32, value: &Value, map: &mut Mapping) -> net::message::Message{
    match value {
        &Value::Number(ref number) => {
            let id = number.as_u64().unwrap() as u32;
            map.put_channel(id, channel);
            let data = json!({"code": "connect_success", "message": "Connect successful."});
            net::message::Message::new(channel, data.to_string())
        },
        _ => {
            error!("Wrong player connect message, can not read player id from json: {:?}", value);
            let data = json!({"code": "connect_failure", "message": "Connect fail. Invalid request format."});
            net::message::Message::new(channel, data.to_string())
        },
    }
}

///
/// 匹配对手消息结构
/// {"code": "user_match", "body": Null}
///
fn handle_player_match(room_sender: &SyncSender<game::message::ChessCommand>,
                       player_sender: &SyncSender<net::message::Message>,
                       queue: &mut Queue,
                       channel: u32,
                       player: u32,
                       map: &Mapping) {
    let command = game::message::ChessCommand::NewRoom(1, 3, 4);
    let opponent = queue.take();
    match opponent {
        Some(opp) => {
            let room = new_room_id();
            let message = game::message::ChessCommand::NewRoom(room, player, opp);
            room_sender.send(message);
            //这里不能回复消息，因为room创建后，会回复消息。
//            let black_rep = json!({"code": "match_success", "turn": true, "opponent": opp});
//            let white_rep = json!({"code": "match_success", "turn": false, "opponent": player});
//            player_sender.send(net::message::Message::new(channel, black_rep.to_string()));
//            let white_channel = map.get_channel(&opp).unwrap();
//            player_sender.send(net::message::Message::new(*white_channel, white_rep.to_string()));
            info!("Player match success. room: {}, black: {}, white: {}", room, player, opp);
        },
        None => {
            queue.push(player);
            let data = json!({"code": "waiting_match", "message": "Waiting for match opponent..."});
            let message = net::message::Message::new(channel, data.to_string());
            player_sender.send(message);
        }
    }
}

///处理落子请求
/// body: {location: u8}
fn handle_put_request(sender: &SyncSender<game::message::ChessCommand>, value: &Value, room: u32, player_id: u32){
    match value {
        &Value::Object(ref map) => {
            let location = map.get("location");
            match location {
                Some(loc) => {
                    match loc {
                        &Value::Number(ref number) => {
                            let index = number.as_u64().unwrap() as u8;
                            let message = game::message::ChessCommand::PutPiece(room, player_id, index);
                            sender.send(message);
                        },
                        _ => error!("error!")
                    }
                }
                _ => error!("error!")
            }
        },
        _ => error!("Unsupported body: {:?}", value),
    }
}

///处理吃子请求
fn handle_kill_request(sender: &SyncSender<game::message::ChessCommand>, value: &Value, room: u32, player_id: u32){
    match value {
        &Value::Object(ref map) => {
            let location = map.get("location");
            match location {
                Some(loc) => {
                    match loc {
                        &Value::Number(ref number) => {
                            let index = number.as_u64().unwrap() as u8;
                            let message = game::message::ChessCommand::KillPiece(room, player_id, index);
                            sender.send(message);
                        },
                        _ => error!("error!")
                    }
                }
                _ => error!("error!")
            }
        },
        _ => error!("Unsupported body: {:?}", value),
    }
}

///处理走子
fn handle_move_request(sender: &SyncSender<game::message::ChessCommand>, value: &Value, room: u32, player_id: u32){
    match value {
        &Value::Object(ref map) => {
            let source = map.get("source").unwrap();
            let target = map.get("target").unwrap();
            match source {
                &Value::Number(ref s) => {
                    let sl = s.as_u64().unwrap() as u8;
                    match target {
                        &Value::Number(ref t) => {
                            let tl = t.as_u64().unwrap() as u8;
                            let message = game::message::ChessCommand::MovePiece(room, player_id, sl, tl);
                            sender.send(message);
                        },
                        _ => error!("error!"),
                    }
                },
                _ => error!("error!")
            }
        },
        _ => error!("Unsupported body: {:?}", value),
    }
}

fn not_connect_error(sender: &SyncSender<net::message::Message>, channel: u32){
    let data = json!({"code": "not_connected", "message": "You have not registered to server. Please regist first."});
    let message = net::message::Message::new(channel, data.to_string());
    sender.send(message);
    info!("A no-connected user come in. channel: {}", channel);
}